/*
 * Licensed to Nanjing RedOrange Co. ltd (RedOrange) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * RedOrange licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package redora.generator;

import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import redora.generator.exceptions.ModelGenerationException;

/**
 * XML utilities in specific use for this project.
 * 
 * @author jaap
*/
public class XMLUtil {

	/**
	 * Transform xml Node with xslt template file to stream 
	 *
	*/
	public static void xsltTransform(Node xml, InputStream xslt, Writer out,
			HashMap<String, String> param) throws TransformerException {
		Source xmlSource = new DOMSource(xml);
		Source xsltSource = new StreamSource(xslt);
		TransformerFactory factory = TransformerFactory.newInstance();
		Transformer transformer = factory.newTransformer(xsltSource);

		for (String key : param.keySet()) {
			transformer.setParameter(key, param.get(key));
		}

		transformer.transform(xmlSource, new StreamResult(out));
	}

	/**
	 * Retrieves the distinct values of all 'language' attributes in given
	 * document.
	 * 
	 * @param doc
	 *            The XML document
	 * @return Empty or filled set.
	 */
	public static Set<String> definedLanguages(Document doc)
			throws XPathExpressionException {
		Set<String> retVal = new HashSet<String>();
	
		XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		NodeList langNodes = (NodeList) xpath.evaluate("//@language", doc,
				XPathConstants.NODESET);
		if (langNodes != null) {
			for (int i = 0; i < langNodes.getLength(); i++) {
				retVal.add(langNodes.item(i).getNodeValue());
			}
			System.out.println("Found " + retVal.size()
					+ " different languages.");
		} else {
			System.out
					.println("No captions found, the client will be using the model attribute names for caption.");
		}
	
		return retVal;
	}

	public static NodeList attributes(Document doc, String filter) throws XPathExpressionException {
	
		XPath xpath = XPathFactory.newInstance().newXPath();
		String query = "/object/attributes/*";
		if (filter != null) {
			query += "[" + filter + "]";
		}
		return (NodeList) xpath.evaluate(query, doc, XPathConstants.NODESET);
	}

	
	/**
	 * Retrieves all enum from model doc.
	 * 
	 * @param doc The model
	 * @param basePackage
	 * @return Empty or filled set.
	 */
	public static Map<String, Document> enumerations(Document doc, String basePackage)
		throws XPathExpressionException, ModelGenerationException {
		Map<String, Document> retVal = new HashMap<String, Document>();
	
		NodeList enumNodes = (NodeList) XPathFactory.newInstance().newXPath()
				.evaluate("//enum[@scope='global']", doc,
						XPathConstants.NODESET);
		if (enumNodes != null) {
			for (int i = 0; i < enumNodes.getLength(); i++) {
				String name = enumNodes.item(i).getAttributes().getNamedItem(
						"class").getNodeValue();
				Document enumDoc = ModelProcessor.newDocument(basePackage, null, "enums");
				ModelProcessor.addChildElement(enumDoc, "name", name);
				enumDoc.getFirstChild().appendChild(
						enumDoc.importNode(enumNodes.item(i), true));
				retVal.put(name, enumDoc);
			}
		} else {
			System.out
					.println("No captions found, the client will be using the model attribute names for caption.");
		}
	
		return retVal;
	}
}
